<!---{
"title": "quick-lint-js: find JavaScript bugs",
"description": "quick-lint-js gives you instant feedback as you code. Find bugs in your JavaScript before your finger leaves the keyboard."
}--->

<!DOCTYPE html>
<!-- Copyright (C) 2020  Matthew "strager" Glazar -->
<!-- See end of file for extended copyright information. -->
<html>
  <head>
    <%- await include("./common-head.ejs.html") %>
    <link href="main.css" rel="stylesheet" />
    <style>
      .feature-comparison table {
        border-collapse: collapse;
        width: 100%;
      }
      .feature-comparison td,
      .feature-comparison th {
        background-color: transparent;
        border-color: #888888;
        border-style: solid;
        border-width: 0;
        padding: 0.5rem 1rem;
        text-align: center;
      }
      .feature-comparison th:first-child {
        text-align: right;
      }
      .feature-comparison tbody td,
      .feature-comparison tbody th {
        border-top-width: 1px;
      }
      .feature-comparison th {
        font-weight: normal;
      }

      .feature-comparison td.quick-lint-js,
      .feature-comparison th.quick-lint-js {
        border-left-width: 1px;
        border-right-width: 1px;
        white-space: nowrap;
      }

      .feature-comparison .footnote-marker {
        position: absolute;
      }

      .feature-comparison figcaption p {
        margin-top: 0.25em;
        margin-bottom: 0.25em;
      }

      /* Make editor logos appear beside the editor names. */
      .feature-comparison .editors th:first-child {
        white-space: nowrap;
      }
      .feature-comparison .editors th:first-child a + a,
      .feature-comparison .editors th:first-child > img.logo,
      .feature-comparison .editors th:first-child > svg.logo {
        margin-left: 0.5rem;
      }

      /* Make the table consume less horizontal space. */
      .feature-comparison .editors tr:not(.header) th:first-child {
        font-size: 75%;
      }

      /* Make the entire cell clickable. (How does this even work???) */
      .feature-comparison table {
        height: 0;
      }
      .feature-comparison td.has-link {
        height: 100%;
        padding: 0;
      }
      .feature-comparison td.has-link > a {
        align-items: center;
        display: flex;
        flex-direction: column;
        height: 100%;
        justify-content: center;
        text-decoration: none;
      }
      .feature-comparison td.has-link > a:hover {
        background-color: rgba(0, 0, 0, 0.05);
      }
      .feature-comparison td.has-link > a {
        /* We want <br> in the markup to improve copy-paste. However, we don't
           want the <br> to take up space because we already use display:flex to
           place things on separate lines.

           <br> doesn't take up any space in Firefox 115.0.3, but does take up
           space in Safari 16.3 and Chromium 111.0.5563.110.

           If we hide the <br>, copy-paste breaks.

           Work around this issue by using &#x0a; and white-space:pre-line
           instead of <br>. This seems to make copy-paste nice while making the
           page look nice visually in all browsers. */
        white-space: pre-line;
      }
      @media (prefers-color-scheme: dark) {
        .feature-comparison td.has-link > a:hover {
          background-color: rgba(255, 255, 255, 0.3);
        }
      }

      .logo {
        height: 1.2rem;
        width: 1.2rem;
        vertical-align: middle;
      }

      .install-options .logo {
        vertical-align: text-bottom;
      }

      #demonstration {
        box-shadow: 0 0 7px rgba(0, 0, 0, 0.6);
        border-radius: 0.75em;
        max-width: 500px;
        margin: 1rem auto;
      }
      /* Make the demonstration look like Visual Studio Code. */
      #demonstration .window-title {
        background-color: #dddddd;
        border-radius: 0.75em 0.75em 0 0;
        border-top: 1px solid #e8e8e8;
        color: #333333;
        font-size: 0.5rem;
        padding: 0.5em;
        position: relative;
        text-align: center;
      }
      #demonstration .traffic-light {
        display: inline-block;
        position: absolute;
        width: 1em;
        height: 1em;
        top: 0.66em;
        border-radius: 1.25em;
      }
      #demonstration .traffic-light-red {
        left: 1em;
        background-color: #ff5e57;
      }
      #demonstration .traffic-light-yellow {
        left: 2.5em;
        background-color: #febd30;
      }
      #demonstration .traffic-light-green {
        left: 4em;
        background-color: #2bc740;
      }
      #demonstration .tab-bar {
        background-color: #f3f3f3;
        color: #333333;
        display: flex;
        flex-direction: row;
        font-size: 0.75rem;
      }
      #demonstration .tab {
        background-color: #ffffff;
        padding: 0.5em 1em;
      }
      #demonstration .tab:before {
        content: "JS";
        padding-left: 0.5em;
        padding-right: 0.5em;
        font-weight: bold;
        font-size: 0.6rem;
        color: #b7b73b;
      }
      #demonstration .tab .close-button {
        display: inline-block;
        padding-left: 0.5em;

        /* When the icon changes, try to keep the center the same. */
        width: 1em;
        text-align: center;
      }
      #demonstration .editor {
        background-color: #ffffff;
        margin: 0;
        padding: 1em 2em;
        font-size: 0.85rem;
        overflow-x: auto;
      }
      #demonstration .footer-bar {
        background-color: #007ad3;
        border-radius: 0 0 0.75em 0.75em;
        color: #ffffff;
        display: flex;
        flex-direction: row;
        font-size: 0.66em;
        justify-content: space-between;
        line-height: 1em;
        padding: 0.25em 1.5em;
      }
      #demonstration .footer-bar img,
      #demonstration .footer-bar svg {
        height: 1em;
        width: 1em;
        vertical-align: bottom;
      }
      @media (prefers-color-scheme: dark) {
        #demonstration .window-title {
          background-color: #3c3c3c;
          border-top-color: #828282;
          color: #cccccc;
        }
        #demonstration .tab-bar {
          background-color: #2d2d2d;
          color: #ffffff;
        }
        #demonstration .tab {
          background-color: #1e1e1e;
        }
        #demonstration .editor {
          background-color: #1e1e1e;
        }
      }

      #demonstration .window-title,
      #demonstration .tab-bar,
      #demonstration .footer-bar {
        user-select: none;
      }

      /* Make a cursor fly in and "fix" the code. */
      #demonstration .to-insert,
      #demonstration .to-remove,
      #demonstration .cursor,
      #demonstration .error-box,
      #demonstration .error-to-fix {
        animation-iteration-count: 1;
        animation-fill-mode: forwards;
        animation-duration: 5s;
      }
      @media (prefers-reduced-motion) {
        #demonstration .to-insert,
        #demonstration .to-remove,
        #demonstration .cursor,
        #demonstration .error-box,
        #demonstration .error-to-fix {
          animation-iteration-count: 0;
        }
      }

      #demonstration .cursor {
        --cursor-radius: 0.75em;
        background-color: rgba(180, 180, 180, 0.6);
        border: 2px solid rgba(180, 180, 180, 0.9);
        border-radius: calc(var(--cursor-radius) * 2);
        content: "";
        height: calc(var(--cursor-radius) * 2);
        position: absolute;
        width: calc(var(--cursor-radius) * 2);

        /* Place the cursor in front of the error box. */
        z-index: 200;
      }
      #demonstration .error-box {
        max-width: initial;
        white-space: nowrap;

        /* Position the error box below the mark. */
        margin-top: 1.25em;

        /* Fix the font because it's inside a pre. */
        font-family: sans-serif;
      }
      #demonstration mark {
        text-decoration-color: red;
        text-decoration-line: underline;
        text-decoration-skip-ink: none;
        text-decoration-style: wavy;
      }
      @media (prefers-color-scheme: dark) {
        #demonstration .cursor {
          background-color: rgba(230, 230, 230, 0.7);
          border-color: rgba(230, 230, 230, 0.9);
        }
      }

      /* Move the cursor from the side to over the erroring code. Then, tap.
         Then, hide the cursor. */
      #demonstration .cursor {
        animation-name: demonstration-cursor;
        margin-top: -0.25em;
        margin-left: 2.5em;
        opacity: 0;
      }
      @keyframes demonstration-cursor {
        0% {
          visibility: visible;
          opacity: 0;
          transform: translate(150px, -30px);
        }
        6% {
          transform: translate(150px, -30px);
        }
        14% {
          opacity: 1;
        }
        30% {
          transform: translate(0, 0);
        }
        65% {
          transform: scale(1, 1);
        }
        70% {
          transform: scale(0.7, 0.7);
        }
        73% {
          transform: scale(1, 1);
        }
        90% {
          opacity: 1;
        }
        95% {
          visibility: visible;
          opacity: 0;
        }
        100% {
          visibility: hidden;
          opacity: 0;
        }
      }
      /* Show the error box when the cursor hovers over it. Then, hide the
         error box when the cursor taps. */
      #demonstration .error-box {
        animation-name: demonstration-error-box;
        opacity: 0;
        position: absolute;
      }
      @keyframes demonstration-error-box {
        0% {
          opacity: 0;
          transform: translate(0, 0.5em);
        }
        20% {
          opacity: 0;
          transform: translate(0, 0.5em);
        }
        30% {
          opacity: 1;
          transform: translate(0, 0);
        }
        73% {
          opacity: 1;
        }
        78% {
          opacity: 0;
        }
        100% {
          opacity: 0;
        }
      }
      /* By default, show the text to remove. Make it disappear when the cursor
         taps. */
      #demonstration .to-remove {
        animation-name: demonstration-to-remove;
        display: inline-block;
        visibility: visible;
        width: auto;
      }
      @keyframes demonstration-to-remove {
        73% {
          width: auto;
          visibility: visible;
        }
        73.001% {
          visibility: hidden;
          width: 0;
        }
        100% {
          visibility: hidden;
          width: 0;
        }
      }
      /* By default, hide the text to insert. Make it appear when the cursor
         taps. */
      #demonstration .to-insert {
        animation-name: demonstration-to-insert;
        display: inline-block;
        visibility: hidden;
        width: 0;
      }
      @keyframes demonstration-to-insert {
        73% {
          width: 0;
          visibility: hidden;
        }
        73.001% {
          visibility: visible;
          width: auto;
        }
        100% {
          visibility: visible;
          width: auto;
        }
      }
      /*decreasing the padding to make the horizontal scroll bar disappear */
      @media only screen and (max-width: 24em) {
        .feature-comparison td,
        .feature-comparison th {
          padding: 0.5rem 0.5rem 0.5rem 0.5rem;
        }
      }
    </style>
    <script>
      //<%
      let {InlineSpriteSheet} = await importFileAsync("../src/sprite-sheet.mjs");
      let spriteSheet = new InlineSpriteSheet({symbolIDPrefix: "sprites-"});
      let vscodeCodiconError = spriteSheet.addSVG(absoluteFilePath("vscode-codicon-error.svg"));
      let vscodeCodiconWarning = spriteSheet.addSVG(absoluteFilePath("vscode-codicon-warning.svg"));
      //%>
    </script>
  </head>
  <body>
    <header><%- await include("./common-nav.ejs.html") %></header>

    <main>
      <p>
        <a href="benchmarks/">Over <strong>90× faster</strong> than ESLint</a>,
        quick-lint-js gives you <strong>instant feedback</strong> as you code.
        <strong>Find bugs</strong> in your JavaScript before your finger leaves
        the keyboard. Lint any JavaScript file with
        <strong>no configuration</strong>.
      </p>

      <figure id="demonstration">
        <div class="window-title">
          <span class="traffic-light traffic-light-red"></span>
          <span class="traffic-light traffic-light-yellow"></span>
          <span class="traffic-light traffic-light-green"></span>
          Your Cool App – Best IDE Ever
        </div>
        <div class="tab-bar">
          <div class="tab">
            AwesomeApp.js
            <span class="close-button">
              <span class="to-remove">✕</span><ins class="to-insert">•</ins>
            </span>
          </div>
        </div>
        <pre
          class="editor"
        ><code class="javascript">const occupation = <mark data-message="variable used before declaration: language" data-code="E0058" data-severity="1">language</mark> + " coder";
const language = "JavaScript";
<mark data-message="assignment to const variable" data-code="E0003" data-severity="1">occupation</mark> = "Senior " + occupation;

<span class="error-box">E0057 - use of undeclared variable: ocupation</span>console.log(`Welcome, ${<span class="cursor"></span><mark class="to-remove" data-message="use of undeclared variable: ocupation" data-code="E0057" data-severity="warning">ocupation</mark><ins class="to-insert">occupation</ins>}!`);

</code></pre>
        <div class="footer-bar">
          <div class="diagnostic-counts">
            <%- vscodeCodiconError.makeReferenceHTML({ alt: "Errors:", width:
            10, height: 10, }) %> 2 <%- vscodeCodiconWarning.makeReferenceHTML({
            alt: "Warnings:", width: 10, height: 10, }) %>
            <span class="to-remove">1</span><ins class="to-insert">0</ins>
          </div>
          <div class="language">JavaScript</div>
        </div>
      </figure>

      <p><a href="demo/">Try it out in your browser.</a></p>

      <%- await spriteSheet.makeInlineHTMLAsync() %>
      <section id="install-section">
        <h2>Install quick-lint-js</h2>
        <p>
          Latest version:
          <a href="releases/" title="Release history"
            ><%= qljsVersionInfo.version %></a
          >
          (released
          <time datetime="<%= qljsVersionInfo.releaseDate %>"
            ><%= new Intl.DateTimeFormat("en-US", {dateStyle: "long", timeZone:
            "UTC"}).format(new Date(qljsVersionInfo.releaseDate)) %></time
          >)
        </p>
        <ul class="install-options">
          <li>
            <a href="install/vscode/plugin/"
              ><qljs-icon
                name="vscode"
                size="19"
                aria-labelledby="install-vs-code"
              />
              <span id="install-vs-code">install VS Code plugin</span></a
            >
          </li>
          <li>
            <a href="install/neovim/"
              ><qljs-icon
                name="neovim"
                size="19"
                aria-labelledby="install-neovim"
              />
              <span id="install-neovim">install Neovim plugin</span></a
            >
          </li>
          <li>
            <a href="install/vim/"
              ><qljs-icon name="vim" size="19" aria-labelledby="install-vim" />
              <span id="install-vim">install Vim plugin</span></a
            >
          </li>
          <li>
            <a href="install/cli/"
              ><qljs-icon
                name="cli-and-lsp-server"
                size="19"
                aria-labelledby="install-cli"
              />
              <span id="install-cli">install CLI</span></a
            >
          </li>
          <li>
            <a href="https://www.npmjs.com/package/quick-lint-js"
              ><qljs-icon name="npm" size="19" aria-labelledby="install-npm" />
              <span id="install-npm">install CLI on npm</span></a
            >
          </li>
        </ul>
        <p>
          <a href="install/">see all installation options</a> &centerdot;
          <a href="releases/">release history</a>
        </p>
      </section>
      <h2 id="linter-feature-comparison">Features</h2>
      <figure class="comparison feature-comparison">
        <table>
          <thead>
            <tr class="header">
              <th class="hide-in-mobile">feature</th>
              <th class="quick-lint-js">quick-lint-js</th>
              <th><a href="https://eslint.org/">ESLint</a></th>
              <th class="hide-in-mobile">
                <a href="https://jshint.com/">JSHint</a>
              </th>
              <th><a href="https://biomejs.dev/">Biome</a></th>
              <th class="hide-in-mobile">
                <a href="https://deno.land/">Deno</a>
              </th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <th class="hide-in-mobile"><a href="benchmarks/">speed</a></th>
              <td class="good quick-lint-js has-link">
                <a href="benchmarks/"
                  ><span aria-labelledby="feature-speed-qljs-quick">🚀</span
                  >&#x0a;<span id="feature-speed-qljs-quick">quick</span></a
                >
              </td>
              <td class="meh">
                <span aria-labelledby="feature-speed-eslint-capable">🐇</span
                ><br /><span id="feature-speed-eslint-capable">capable</span>
              </td>
              <td class="bad hide-in-mobile">
                <span aria-labelledby="feature-speed-jshint-slow">🐢</span
                ><br /><span id="feature-speed-jshint-slow">slow</span>
              </td>
              <td class="good">
                <span aria-labelledby="feature-speed-biome-quick">🚀</span
                ><br /><span id="feature-speed-biome-quick">quick</span>
              </td>
              <td class="bad hide-in-mobile">
                <span aria-labelledby="feature-speed-deno-lint-slow">🐢</span
                ><br /><span id="feature-speed-deno-lint-slow">slow</span>
              </td>
            </tr>
            <tr>
              <th class="hide-in-mobile">easy setup</th>
              <td class="good quick-lint-js">
                <span aria-label="easy">✅</span><br />zero config
              </td>
              <td class="meh">
                <span aria-label="hard">❌</span><br />config or
                <code>init</code>
              </td>
              <td class="bad hide-in-mobile">
                <span aria-label="hard">❌</span><br />config
              </td>
              <td class="good">
                <span aria-label="easy">✅</span><br />config optional
              </td>
              <td class="good hide-in-mobile">
                <span aria-label="easy">✅</span><br />zero config
              </td>
            </tr>
            <tr class="hide-in-mobile">
              <th>easy npm install</th>
              <td class="good quick-lint-js">
                <span aria-label="easy">✅</span>
              </td>
              <td class="good"><span aria-label="easy">✅</span></td>
              <td class="good"><span aria-label="easy">✅</span></td>
              <td class="good"><span aria-label="easy">✅</span></td>
              <td class="bad"><span aria-label="hard">❌</span></td>
            </tr>
            <tr>
              <th class="hide-in-mobile">license</th>
              <td class="good quick-lint-js">free<br />GPLv3</td>
              <td class="meh">open source<br />MIT</td>
              <td class="meh hide-in-mobile">open source<br />MIT</td>
              <td class="meh">open source<br />MIT</td>
              <td class="meh hide-in-mobile">open source<br />MIT</td>
            </tr>
            <tr>
              <th class="hide-in-mobile">JSX</th>
              <td class="good quick-lint-js">
                <span aria-label="yes">✅</span
                ><span class="show-in-mobile"><br />JSX</span>
              </td>
              <td class="meh">
                <span aria-label="yes">✅</span
                ><span
                  aria-label="with plugin"
                  title="with plugin"
                  class="footnote-marker"
                  >&nbsp;†</span
                ><span class="show-in-mobile"><br />JSX</span>
              </td>
              <td class="bad hide-in-mobile">
                <span aria-label="no">❌</span>
              </td>
              <td class="good">
                <span aria-label="yes">✅</span
                ><span class="show-in-mobile"><br />JSX</span>
              </td>
              <td class="good hide-in-mobile">
                <span aria-label="yes">✅</span>
              </td>
            </tr>
            <tr>
              <th class="hide-in-mobile">TypeScript</th>
              <td class="good quick-lint-js">
                <span aria-label="yes">✅</span
                ><span class="show-in-mobile"><br />TypeScript</span>
              </td>
              <td class="meh">
                <span aria-label="yes">✅</span
                ><span
                  aria-label="with plugin"
                  title="with plugin"
                  class="footnote-marker"
                  >&nbsp;<a href="https://typescript-eslint.io/">†</a></span
                ><span class="show-in-mobile"><br />TypeScript</span>
              </td>
              <td class="bad hide-in-mobile">
                <span aria-label="no">❌</span>
              </td>
              <td class="good">
                <span aria-label="yes">✅</span
                ><span class="show-in-mobile"><br />TypeScript</span>
              </td>
              <td class="good hide-in-mobile">
                <span aria-label="yes">✅</span>
              </td>
            </tr>

            <tr>
              <th class="hide-in-mobile">lint rules</th>
              <td class="meh quick-lint-js">
                <a href="errors/">minimal</a
                ><span class="show-in-mobile"><br />lint rules</span>
              </td>
              <td class="good">
                <a href="https://eslint.org/docs/rules/">zillions</a
                ><span class="show-in-mobile"><br />of lint rules</span>
              </td>
              <td class="meh hide-in-mobile">
                <a href="https://jshint.com/docs/options/">some</a>
              </td>
              <td class="meh">
                <a href="https://biomejs.dev/linter/rules/">some</a
                ><span class="show-in-mobile"><br />lint rules</span>
              </td>
              <td class="meh hide-in-mobile">
                <a href="https://lint.deno.land/">some</a>
              </td>
            </tr>
            <tr class="hide-in-mobile">
              <th>stable</th>
              <td class="good quick-lint-js">
                <span aria-label="stable">✅</span>
              </td>
              <td class="good"><span aria-label="stable">✅</span></td>
              <td class="good"><span aria-label="stable">✅</span></td>
              <td class="good"><span aria-label="stable">✅</span></td>
              <td class="good"><span aria-label="stable">✅</span></td>
            </tr>
          </tbody>

          <tbody class="editors hide-in-mobile">
            <tr class="header">
              <th>feature</th>
              <th class="quick-lint-js">quick-lint-js</th>
              <th><a href="https://eslint.org/">ESLint</a></th>
              <th><a href="https://jshint.com/">JSHint</a></th>
              <th><a href="https://biomejs.dev/">Biome</a></th>
              <th><a href="https://deno.land/">Deno</a></th>
            </tr>
            <tr>
              <th class="has-link">
                <a href="install/vscode/">VS Code</a>
                <a href="install/vscode/"
                  ><qljs-icon name="vscode" size="19"
                /></a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/vscode/" aria-label="yes">✅</a>
              </td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
            <tr>
              <th class="has-link">
                <a href="install/vim/">Vim</a>
                <a href="install/vim/"><qljs-icon name="vim" size="19" /></a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/vim/" aria-label="yes">✅</a>
              </td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
            <tr>
              <th class="has-link">
                <a href="install/neovim/">Neovim</a>
                <a href="install/neovim/"
                  ><qljs-icon name="neovim" size="19"
                /></a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/neovim/" aria-label="yes">✅</a>
              </td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
            <tr>
              <th>
                WebStorm
                <qljs-icon name="webstorm" size="19" />
              </th>
              <td class="bad quick-lint-js"><span aria-label="no">❌</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
            <tr>
              <th class="has-link">
                <a href="install/sublime/">Sublime Text</a>
                <a href="install/sublime/"
                  ><qljs-icon name="sublime-text" size="19"
                /></a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/sublime/" aria-label="yes">✅</a>
              </td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
            <tr>
              <th>
                Notepad++
                <qljs-icon name="notepad-plus-plus" size="19" />
              </th>

              <td class="bad quick-lint-js"><span aria-label="no">❌</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
            </tr>
            <tr>
              <th>
                <a href="install/emacs/">Emacs</a>
                <a href="install/emacs/"
                  ><qljs-icon name="emacs" size="19"
                /></a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/emacs/" aria-label="yes">✅</a>
              </td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
            <tr>
              <th>
                Codespaces
                <qljs-icon name="codespaces" size="19" />
              </th>
              <td class="bad quick-lint-js"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
            </tr>
            <tr>
              <th class="has-link">
                <a href="install/kate/">Kate</a>
                <a href="install/kate/"><qljs-icon name="kate" size="19" /></a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/kate/" aria-label="yes">✅</a>
              </td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
            </tr>
            <tr>
              <th class="has-link">
                <a href="install/cli/">LSP server</a>
              </th>
              <td class="good quick-lint-js has-link">
                <a href="install/cli/" aria-label="yes">✅</a>
              </td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="bad"><span aria-label="no">❌</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
              <td class="good"><span aria-label="yes">✅</span></td>
            </tr>
          </tbody>
        </table>
        <figcaption>
          <p id="footnote-with-plugin">
            <span aria-label="planned with plugin">†</span> feature requires a
            plugin
          </p>
        </figcaption>
      </figure>
      <figure id="editors-support" class="show-in-mobile">
        <h2>Editor support</h2>
        <div id="supported-editors">
          <a href="install/vscode/"
            ><qljs-icon name="vscode" size="32" /><br />VS Code</a
          >

          <a href="install/vim/"><qljs-icon name="vim" size="32" /><br />Vim</a>
          <a href="install/neovim/"
            ><qljs-icon name="neovim" size="32" /><br />Neovim</a
          >
          <a href="install/sublime/"
            ><qljs-icon name="sublime-text" size="32" /><br />Sublime Text</a
          >
          <a href="install/emacs/"
            ><qljs-icon name="emacs" size="32" /><br />Emacs</a
          >
          <a href="install/kate/"
            ><qljs-icon name="kate" size="32" /><br />Kate</a
          >
        </div>
      </figure>
    </main>

    <footer><%- await include("./common-footer-nav.ejs.html") %></footer>

    <script src="error-box.bundled.js"></script>
  </body>
</html>

<!--
quick-lint-js finds bugs in JavaScript programs.
Copyright (C) 2020  Matthew "strager" Glazar

This file is part of quick-lint-js.

quick-lint-js is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

quick-lint-js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with quick-lint-js.  If not, see <https://www.gnu.org/licenses/>.
-->
<!--
Other files may have different copyright and may be licensed under different
licenses. See license/ for details.
-->
